package com.nuoniu.sibanyun.service.erp.in.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.microsoft.schemas.office.visio.x2012.main.CellType;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.common.text.PinyinUtils;
import com.nuoniu.sibanyun.entity.bo.UnExecutedBo;
import com.nuoniu.sibanyun.entity.dto.InInventoryPageSearchDto;
import com.nuoniu.sibanyun.entity.dto.InInventorySaveDto;
import com.nuoniu.sibanyun.entity.dto.InInventorySearchDto;
import com.nuoniu.sibanyun.entity.erp.ErpVoucherTable;
import com.nuoniu.sibanyun.entity.erp.in.*;
import com.nuoniu.sibanyun.entity.vo.InInventoryPropertyVo;
import com.nuoniu.sibanyun.mapper.erp.in.InInventoryMapper;
import com.nuoniu.sibanyun.mapper.erp.in.InUnitMapper;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherTableService;
import com.nuoniu.sibanyun.service.erp.in.IInInventoryClassService;
import com.nuoniu.sibanyun.service.erp.in.IInInventoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.service.inOut.IVInOutRecordDetailService;
import com.nuoniu.sibanyun.service.po.IVPurchaseArrivalDetailService;
import com.nuoniu.sibanyun.service.production.IVProductionWorkInventoryDetailService;
import com.nuoniu.sibanyun.service.so.IVSaleDeliveryDetailService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import com.nuoniu.sibanyun.utils.ExcelUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 物料档案 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-09-22
 */
@Service
public class InInventoryServiceImpl extends ServiceImpl<InInventoryMapper, InInventory> implements IInInventoryService {

    @Autowired
    private IErpAccountService accountService;
    @Autowired
    @Lazy
    private IInInventoryClassService inventoryClassService;
    @Autowired
    private IErpVoucherTableService voucherTableService;

    @Autowired
    @Lazy
    private IVProductionWorkInventoryDetailService productionWorkInventoryDetailService;

    @Autowired
    private IVPurchaseArrivalDetailService purchaseArrivalDetailService;

    @Autowired
    private IVSaleDeliveryDetailService saleDeliveryDetailService;
    @Autowired
    private IVInOutRecordDetailService ivInOutRecordDetailService;
    @Autowired
    private InUnitMapper unitMapper;

    //入库前置业务（）
    private static final  String[] InVoucherCodesArr
            = {"PurchaseOrder","PuArrival","ProductionOrder","ProductionWork","ProductionFinish"};
    //出库前置业务()
    private static final  String[] OutVoucherCodesArr
            = {"SaleOrder","SaleDelivery","RRS","DelegateRRS"};

    private static final  String[] InInventoryPropertyArr = {"is_purchasing","is_for_sale","is_made_self","is_semi_manufactured","is_material","is_labor_cost","is_suite","is_made_request","is_invented_key"};

    //2.检查 物料计量单位 是否是多计量单位
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Long saveInInventory(InInventorySaveDto inInventorySaveDto) {
        InInventory inInventory = inInventorySaveDto.getInInventory();
        if (StringUtils.isBlank(inInventory.getInventoryName())) {
            throw new NuoNiuException("物料档案名称和规格型号已存在");
        }

        if (StringUtils.isBlank(inInventory.getInventoryCode())) {
            throw new NuoNiuException("物料档案编码不能为空");
        }

        if (null == inInventory.getInventoryClassId()) {
            throw new NuoNiuException("物料分类不能为空");
        }

        String unitType = inInventory.getUnitType();
        if (null == unitType) {
            throw new NuoNiuException("计量方式不能为空");
        }

        InInventoryClass inventoryClass = inventoryClassService.getById(inInventory.getInventoryClassId());
        if (inventoryClass == null) {
            throw new NuoNiuException("物料分类不存在");
        }
        inInventory.setInventoryClassName(inventoryClass.getTreeNames());

        if (!inventoryClass.getClassEnd()) {
            throw new NuoNiuException("只能在物料分类末级新增物料");
        }

        UserInfo userInfo = UserThreadLocal.get();
        inInventory.setCompanyId(userInfo.getCompanyId());
        InInventory inventoryCode = baseMapper.getByCode(inInventory);
        InInventory inventoryByName = baseMapper.getByName(inInventory);

        if (inventoryCode != null) {
            if (inInventory.getId() == null || !(inventoryCode.getId().equals(inInventory.getId()))) {
                throw new NuoNiuException("编码已存在");
            }
        }

        if (inventoryByName != null) {
            if (inInventory.getId() == null || !(inventoryByName.getId().equals(inInventory.getId()))) {
                throw new NuoNiuException("此规格型号下的物料名称已存在");
            }
        }

        //判断编码规则
        //accountingService.checkCode(inInventory.getInventoryCode(), inventoryClass.getClassCode(), inventoryClass.getClassGrade(), "inventoryclass");
        if (!inInventory.getInventoryCode().startsWith(inventoryClass.getClassCode()) || inInventory.getInventoryCode().length() <= inventoryClass.getClassCode().length()) {
            throw new NuoNiuException("请输入物料编码");
        }

        if (inInventory.getId() != null) {
//            InInventory oldInventory = this.getById(inInventory.getId());
//            if (!oldInventory.getInventoryCode().equals(inInventory.getInventoryCode())) {
//                throw new NuoNiuException("保存后，编码不能修改");
//            }

            inInventory.setInventoryCode(null);
            inInventory.setInventoryClassName(null);
            inInventory.setInventoryClassId(null);
            inInventory.setUpdateUserId(userInfo.getUserId());
            inInventory.setUpdateUserName(userInfo.getRealName());
            inInventory.setUpdateDate(LocalDateTime.now());
        } else {
            inInventory.setAccountId(accountService.getCurrentAccountId());
            inInventory.setCreateUserId(userInfo.getUserId());
            inInventory.setCreateUserName(userInfo.getRealName());
        }

        saveOrUpdate(inInventory);
        return inInventory.getId();
    }

    @Override
    public List<InInventory> getByClass(Integer id) {
        return baseMapper.getByClass(id);
    }

    @Override
    public Page<InInventory> pageList(Page pages, InInventoryPageSearchDto inInventoryPageSearchDto) {
        String inventoryClassCode = inInventoryPageSearchDto.getInventoryClassCode();
        String inventoryCode = inInventoryPageSearchDto.getInventoryCode();
        String inventoryName = inInventoryPageSearchDto.getInventoryName();
        String inventorySpecification = inInventoryPageSearchDto.getInventorySpecification();
        UserInfo userInfo = UserThreadLocal.get();

        QueryWrapper<InInventory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id", userInfo.getCompanyId());
        if(StringUtils.isNotBlank(inventoryClassCode)){
            queryWrapper.likeRight("inventory_code", inventoryClassCode);
        }
        if(StringUtils.isNotBlank(inventoryCode)) {
            queryWrapper.like("inventory_code", inventoryCode);
        }
        if(StringUtils.isNotBlank(inventorySpecification)) {
            queryWrapper.like("inventory_specification", inventorySpecification);
        }
        if(StringUtils.isNotBlank(inventoryName)) {
            queryWrapper.like("inventory_name", inventoryName);
        }
        if(StringUtils.isNotBlank(inInventoryPageSearchDto.getSearchKey())) {
            queryWrapper.and(wrapper -> wrapper.like("inventory_code", inInventoryPageSearchDto.getSearchKey()).or().like("inventory_name", inInventoryPageSearchDto.getSearchKey()).or().like("inventory_specification", inInventoryPageSearchDto.getSearchKey()));
        }
        queryWrapper.orderByAsc("inventory_code");
        Page page = page(pages, queryWrapper);
        return page;
    }

    @Override
    public void updateWarehouse(InWarehouse inWarehouse) {
        baseMapper.updateWarehouse(inWarehouse);
    }

    @Override
    public InInventory getByCode(InInventory inInventory) {
        return baseMapper.getByCode(inInventory);
    }

    @Override
    public InInventory getByName(InInventory inInventory) {
        return baseMapper.getByName(inInventory);
    }

    @Override
    public List<InInventory> getByUnitId(Integer id) {
        return baseMapper.getByUnitId(id, UserThreadLocal.get().getCompanyId());
    }

    @Override
    public List<InInventory> getByUnitGroupId(Integer unitGroupId) {
        return baseMapper.getByUnitGroupId(unitGroupId, UserThreadLocal.get().getCompanyId());
    }

    @Override
    public Page<InInventory> getList(Page pages, InInventorySearchDto inInventorySearchDto) {
        String inInventoryClassCode = inInventorySearchDto.getInInventoryClassCode();
        String key = inInventorySearchDto.getKey();
        String propertyStr = inInventorySearchDto.getPropertyStr();
        Long inInventoryClassId = inInventorySearchDto.getInInventoryClassId();
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<InInventory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id", userInfo.getCompanyId());
        if (null != inInventoryClassId){
            queryWrapper.eq("inventory_class_id",inInventoryClassId);
        }
        if(StringUtils.isNotBlank(inInventoryClassCode)){
            queryWrapper.likeRight("inventory_code",inInventoryClassCode);
        }
        if(StringUtils.isNotBlank(key)) {
            queryWrapper.and(wrapper -> wrapper.like("inventory_code", key).or().like("inventory_name", key).or().like("inventory_specification", key));
        }
        // 配置 存货属性
        if (StringUtils.isNotBlank(propertyStr)){
            String[] propertyList = propertyStr.split(",");
            List<String> InInventoryPropertyList = Arrays.asList(InInventoryPropertyArr);
            queryWrapper.and(wrapper -> {
                boolean isFirst = true;
                for (int i = 0; i < propertyList.length; i++) {
                    String property = propertyList[i];
                    if (InInventoryPropertyList.contains(property));
                    if(isFirst){
                        wrapper.eq(property, 1);
                        isFirst = false;
                    }else {
                        wrapper.or().eq(property, 1);
                    }
                }
            });
        }
        queryWrapper.orderByAsc("inventory_code");
        Page<InInventory> page = page(pages, queryWrapper);
        page.getRecords().forEach(i -> {
            i.setReferenceCost(null);
            i.setMinSellingPrice(null);
            i.setSellingPrice(null);
            i.setLatestCost(null);
        });
        return page;
    }

    @Override
    public Integer getByUnit(Long id) {
        return baseMapper.getByUnit(id);
    }

    @Override
    @Async
    @Transactional
    public void updateBillInventory(InInventory inInventory) {
        String[] tableName = {"mab_bom_detail", "mab_bom", "scw_delivery_entry_detail", "scp_receiving_detail", "scp_invoice_detail", "scp_order_detail",
                "scp_requisition_detail", "scs_delivery_detail", "scs_invoice_detail", "scs_order_detail", "scs_quotation_detail", "ma_completed_prod_detail",
                "ma_prod_order_detail", "ma_completed_prod_detail", "ma_prod_order_detail", "ma_picking_return_rep_detail", "ma_mps_detail", "ma_written_instruction_detail"};
        for(int i=0; i<tableName.length; i++) {
            baseMapper.updateBillInventory(tableName[i], inInventory.getId(), inInventory.getInventoryName(), inInventory.getInventorySpecification());
        }
    }

    /**
     * 根据传来的生产制造或者仓库id删除删除
     * @param ids
     */
    @Override
    public void deleteByIds(List<Integer> ids) {
        String[] tableName = {"mab_bom_detail", "mab_bom", "scw_delivery_entry_detail", "scp_receiving_detail", "scp_invoice_detail", "scp_order_detail", "ma_prod_order_detail",
                "scp_requisition_detail", "scs_delivery_detail", "scs_invoice_detail", "scs_order_detail", "scs_quotation_detail", "ma_picking_return_rep_detail", "ma_completed_prod_detail",
                "ma_prod_order_detail", "ma_mps_detail", "ma_written_instruction_detail"};

        String[] tableChineseName = {"bom明细", "bom主表", "出入库", "采购到货单", "采购发票", "采购订单", "生产订单",
                "请购单", "销售发货", "销售发票", "销售订单", "报价单", "生产领退补", "生产完工",
                "生产订单", "生产计划", "生产加工"};
        for(int i=0; i<tableName.length; i++) {
           Integer count = baseMapper.getBillInventory(tableName[i], StringUtils.join(ids, ","));
           if(count > 0) {
               throw new NuoNiuException("在'" + tableChineseName[i] + "'中使用,不能删除");
           }
        }

        removeByIds(ids);
    }

    @Override
    public List<InInventory> getByWarehouse(String warehouseIds) {
        return baseMapper.getByWarehouse(warehouseIds);
    }

    @Override
    public List<UnExecutedBo> getUnExecuteQuantity(String mainTableName, String detailTableName, String inventoryIds,String warehouseIds) {
        Integer currentAccountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        List<UnExecutedBo> unExecuteQuantityList = baseMapper.getUnExecuteQuantityList(mainTableName, detailTableName, userInfo.getCompanyId(), currentAccountId, inventoryIds,warehouseIds);
        return unExecuteQuantityList;
    }
    /**
     * 获取某些物料的 可用量
     * @param inventoryIdSet
     * @return
     */
    @Override
    public HashMap<Integer, BigDecimal> getAvailableQuantityMap(Set<Integer> inventoryIdSet,Set<Integer> warehouseIdSet) {
        List<String> inVoucherCodes = Arrays.asList(InVoucherCodesArr);
        List<String> outVoucherCodes = Arrays.asList(OutVoucherCodesArr);
        HashMap<Integer, BigDecimal> availableQuantityMap = new HashMap<>();
        inventoryIdSet.forEach(inventoryId -> availableQuantityMap.put(inventoryId,new BigDecimal(0)));
        List<ErpVoucherTable> tableList = voucherTableService.list();
        String inventoryIdStr = StringUtils.join(inventoryIdSet, ",");

        // 获取 未执行 数量
        tableList.forEach(table->{
            String voucherTypeCode = table.getVoucherTypeCode();
            //是否 是出入库 前置业务
            if (inVoucherCodes.contains(voucherTypeCode) || outVoucherCodes.contains(voucherTypeCode)){
                String warehouseIdStr = "";
                if(null != warehouseIdSet && warehouseIdSet.size() > 0){
                    warehouseIdStr = StringUtils.join(warehouseIdSet, ",");
                }
                List<UnExecutedBo> unExecuteQuantityList = getUnExecuteQuantity(table.getTableName(), table.getDetailTableName(), inventoryIdStr,warehouseIdStr);
                unExecuteQuantityList.forEach(unExecuteQuantity->{
                    BigDecimal unExecuted = unExecuteQuantity.getUnExecuted();
                    if (unExecuted.compareTo(BigDecimal.ZERO) > 0){
                        Integer inventoryId = unExecuteQuantity.getInventoryId();
                        BigDecimal bigDecimal = availableQuantityMap.get(inventoryId);
                        //入库前置业务 做加法
                        if (inVoucherCodes.contains(voucherTypeCode)){
                            bigDecimal = bigDecimal.add(unExecuted);
                        }
                        //出库前置业务 做减法
                        else if(outVoucherCodes.contains(voucherTypeCode)){
                            bigDecimal = bigDecimal.subtract(unExecuted);
                        }
                        availableQuantityMap.put(inventoryId,bigDecimal);
                    }
                });
            }
        });

        String warehouseIdStr2 = "";
        if(null != warehouseIdSet && warehouseIdSet.size() > 0){
            warehouseIdStr2 = StringUtils.join(warehouseIdSet, ",");
        }
        // 获取 加工单 物料明细 未执行量(出库前置业务)
        List<UnExecutedBo> inventoryDetailUnExecuteQuantityList = productionWorkInventoryDetailService.getUnExecuteQuantity(inventoryIdStr,warehouseIdStr2);
        inventoryDetailUnExecuteQuantityList.forEach(unExecuteQuantity->{
            BigDecimal unExecuted = unExecuteQuantity.getUnExecuted();
            if (unExecuted.compareTo(BigDecimal.ZERO) > 0){
                Integer inventoryId = unExecuteQuantity.getInventoryId();
                BigDecimal bigDecimal = availableQuantityMap.get(inventoryId);
                availableQuantityMap.put(inventoryId,bigDecimal.subtract(unExecuted));
            }
        });

        // 获取 采购退货数量 和 销售退货 未执行量 (因退货明细的数量 是负数，所以需要单独处理)
        //1.采购退货数量 (包括委外退货)
        List<UnExecutedBo> puRetUnExecuteQuantity = purchaseArrivalDetailService.getRetUnExecuteQuantity(inventoryIdStr,warehouseIdStr2);
        puRetUnExecuteQuantity.forEach(unExecuteQuantity->{
            BigDecimal unExecuted = unExecuteQuantity.getUnExecuted();
            if (unExecuted.compareTo(BigDecimal.ZERO) < 0){
                Integer inventoryId = unExecuteQuantity.getInventoryId();
                BigDecimal bigDecimal = availableQuantityMap.get(inventoryId);
                availableQuantityMap.put(inventoryId,bigDecimal.add(unExecuted));
            }
        });

        //2.销售退货 未执行量
        List<UnExecutedBo> saRetUnExecuteQuantity = saleDeliveryDetailService.getRetUnExecuteQuantity(inventoryIdStr,warehouseIdStr2);
        saRetUnExecuteQuantity.forEach(unExecuteQuantity->{
            BigDecimal unExecuted = unExecuteQuantity.getUnExecuted();
            if (unExecuted.compareTo(BigDecimal.ZERO) < 0){
                Integer inventoryId = unExecuteQuantity.getInventoryId();
                BigDecimal bigDecimal = availableQuantityMap.get(inventoryId);
                availableQuantityMap.put(inventoryId,bigDecimal.subtract(unExecuted));
            }
        });

        //获取 待入库 和 待出库 的数量
        List<UnExecutedBo> InOutUnExecuteQuantityList = ivInOutRecordDetailService.getUnExecuteQuantityList(inventoryIdStr,warehouseIdStr2);
        InOutUnExecuteQuantityList.forEach(unExecuteQuantity->{
            BigDecimal unExecuted = unExecuteQuantity.getUnExecuted();
            if (unExecuted.compareTo(BigDecimal.ZERO) != 0){
                Integer inventoryId = unExecuteQuantity.getInventoryId();
                BigDecimal bigDecimal = availableQuantityMap.get(inventoryId);
                availableQuantityMap.put(inventoryId,bigDecimal.add(unExecuted));
            }
        });

        return availableQuantityMap;
    }

    @Override
    public HashMap<Integer, HashMap<String, BigDecimal>> getInventoryQuantity(Set<Integer> inventoryIdList) {
        HashMap<Integer, HashMap<String, BigDecimal>> resultMap = new HashMap<>();
        Integer currentAccountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        String inventoryIdStr = StringUtils.join(inventoryIdList, ",");
        //可用量
        HashMap<Integer, BigDecimal> availableQuantityMap = getAvailableQuantityMap(inventoryIdList,null);
        List<InInventoryInfo> inInventories = baseMapper.listExistingQuantity(userInfo.getCompanyId(), currentAccountId, inventoryIdStr);
        HashMap<Integer,BigDecimal> existingQuantityMap = new HashMap<>();
        inInventories.forEach(inInventoryInfo -> existingQuantityMap.put(inInventoryInfo.getInventoryId(),inInventoryInfo.getInventoryQuantity()));
        inventoryIdList.forEach(inventoryId->{
            HashMap<String, BigDecimal> stringBigDecimalHashMap = resultMap.get(inventoryId);
            if (null == stringBigDecimalHashMap){
                stringBigDecimalHashMap = new HashMap<>();
                resultMap.put(inventoryId,stringBigDecimalHashMap);
            }
            stringBigDecimalHashMap.put("existingQuantity",existingQuantityMap.get(inventoryId));
            stringBigDecimalHashMap.put("availableQuantity",availableQuantityMap.get(inventoryId));
        });
        return resultMap;
    }

    @Override
    @Async
    public void updateInventoryClass(InInventoryClass inInventoryClass) {
        baseMapper.updateInventoryClass(inInventoryClass);
    }

    @Override
    public void importTemplate(HttpServletResponse response) {
        //填充模版数据
        String fileName = "导入物料档案模板.xls";
        String[] data = {"001", "山城啤酒(*多计量只需填计量单位组)", "LL-678", "单计量", "", "瓶", "是", "否", "否", "否", "否", "否", "否", "99", "98", "20", "5", "全月平均"};
        Object[] title = {"物料编码", "物料名称", "规格型号","计量方式", "计量单位组", "计量单位", "允许外购", "允许销售", "允许自制", "允许委外", "允许生产耗用", "允许劳务费用", "允许成套件", "最低库存", "最高库存", "安全库存", "采购提前期(天)", "计价方式"};
        ExcelUtils.export(title,fileName, data, response);
    }

    @Override
    @Transactional
    public Map importData(MultipartFile file, boolean b, String[] excelFiled, String[] dbFiled, Integer classId) throws IOException {
        UserInfo userInfo = UserThreadLocal.get();
        //成功个数
        Integer successNum = 0;
        //失败个数
        Integer failureNum = 0;
        //失败原因
        List<String> failCauseList = new ArrayList<>();
        //失败数据
        List<List<String>> failDataList = new ArrayList<>();
        //物料数据
        List<InInventory> inventoryList = new ArrayList<>();
        //物料名称标记
        Map<String, InInventory> inNameMap = new HashMap();
        //物料编码标记
        Map<String, InInventory> inCodeMap = new HashMap<>();

        boolean isExcel2003 = true;
        if (file.getOriginalFilename().matches("^.+\\.(?i)(xlsx)$")) {
            isExcel2003 = false;
        }

        //解析excel
        InputStream is = file.getInputStream();
        Workbook wb;
        if (isExcel2003) {
            wb = new HSSFWorkbook(is);
        } else {
            wb = new XSSFWorkbook(is);
        }

        Sheet sheet = wb.getSheetAt(0);
        if(sheet.getLastRowNum() > 10000) {
            throw new NuoNiuException("每次导入不能超过5000条数据");
        }

        //获取已存在物料名称
        String[] inventoryNameArr = baseMapper.getByInventoryNames(userInfo.getCompanyId());
        //获取已存在的物料编码
        String[] inventoryCodeArr = baseMapper.getInventoryCodes(userInfo.getCompanyId(), classId);
        //获取单计量名称
        List<String> unitNameList = unitMapper.getNameList(userInfo.getCompanyId());
        //获取计量分组名称
        List<String> groupNameList = unitMapper.getGroupNameList(userInfo.getCompanyId());
        //获取物料分类
        InInventoryClass inventoryClass = inventoryClassService.getById(classId);
        //获取当前分类最大编码
        Integer inCode = 1;
        String code = baseMapper.getMaxCodeByClassId(classId, inventoryClass.getClassCode().length());
        if(code == null) {
            code = "";
        }

        for (int r = 1; r <= sheet.getLastRowNum(); r++) { //循环excel行读取数据
            List<String> cellData = new ArrayList<>();
            Row row = sheet.getRow(r);
            InInventory inventory = new InInventory();
            Boolean flag = true;
            try {
                for(int i=0; i<excelFiled.length; i++) {
                    if(row == null || row.getCell(i) ==  null) {
                        continue;
                    }

                    row.getCell(i).setCellType(CellType.GREATER_THAN);
                    String cellValue = (row.getCell(i).getStringCellValue() + "").trim();
                    if(StringUtils.isNotBlank(cellValue)) {
                        flag = false;
                    }
                    cellData.add(cellValue);
                    if(dbFiled.length > i && StringUtils.isNotBlank(dbFiled[i]) && StringUtils.isNotBlank(cellValue)) {
                        Class crmCompanyClass = inventory.getClass();
                        Field f = crmCompanyClass.getDeclaredField(dbFiled[i]);
                        f.setAccessible(true);

                        //设置物料属性
                        if(dbFiled[i].equals("isPurchasing") || dbFiled[i].equals("isForSale") || dbFiled[i].equals("isMadeSelf") || dbFiled[i].equals("isMaterial")
                                || dbFiled[i].equals("isLaborCost") || dbFiled[i].equals("isSuite") || dbFiled[i].equals("isMadeRequest")) {
                            Boolean bValue = (StringUtils.isBlank(cellValue) || cellValue.equals("0") || cellValue.equals("否") || cellValue.equals("false")) ? false : true;
                            f.set(inventory, bValue);
                            continue;
                        }

                        if(dbFiled[i].equals("minStorage") || dbFiled[i].equals("maxStorage") || dbFiled[i].equals("safeStorage")) {
                            try {
                                f.set(inventory, new BigDecimal(cellValue));
                                continue;
                            } catch (Exception e) {
                                failCauseList.add("第" + (r + 1) + "行:" + "最高/最低/安全库存只是填数字或为空！");
                                break;
                            }
                        }

                        if(dbFiled[i].equals("purchasingLeadTime")) {
                            f.set(inventory, Integer.valueOf(cellValue));
                            continue;
                        }

                        try {
                            f.set(inventory, cellValue);
                        } catch (Exception e) {
                            e.printStackTrace();
                            continue;
                        }

                    }
                }
            } catch (Exception e) { //自定义字段
                e.printStackTrace();
                continue;
            }

            if(flag) {
                continue;
            }

            //检查物料
            Boolean checkResult = checkInventory(inventory, failCauseList, r, unitNameList, groupNameList);
            if(!checkResult) {
                failureNum++;
                failDataList.add(cellData);
                continue;
            }

            if(StringUtils.isBlank(inventory.getInventoryCode())) {
                inventory.setInventoryCode(inventoryClass.getClassCode() + code + (inCode++).toString());
            }else {
                inventory.setInventoryCode(inventoryClass.getClassCode() + inventory.getInventoryCode());
            }

            if(Arrays.asList(inventoryCodeArr).contains(inventory.getInventoryCode()) || inCodeMap.get(inventory.getInventoryCode()) != null) { //存货编码不能重复
                failCauseList.add("第" + (r + 1) + "行:" + "物料编码已存在");
                failDataList.add(cellData);
                failureNum ++;
                continue;
            }

            inCodeMap.put(inventory.getInventoryCode(), inventory);
            if(!Arrays.asList(inventoryNameArr).contains(inventory.getInventoryName().trim() + inventory.getInventorySpecification()) && inNameMap.get(inventory.getInventoryName() + inventory.getInventorySpecification()) == null) { //存货名称不能重复
                inventory.setCompanyId(userInfo.getCompanyId());
                inNameMap.put(inventory.getInventoryName() + inventory.getInventorySpecification(), inventory);
                inventory.setCreateUserId(userInfo.getUserId());
                inventory.setCreateUserName(userInfo.getRealName());
                inventory.setInventoryClassId(inventoryClass.getId().intValue());
                inventory.setInventoryClassName(inventoryClass.getTreeNames());
                if(inventory.getPyCode() != null) {
                    inventory.setPyCode(PinyinUtils.getFirstSpell(inventory.getInventoryName()));
                }
                inventoryList.add(inventory);
                successNum ++;
            }else {
                failCauseList.add("第" + (r + 1) + "行:" + "同一规格型号，物料名称已存在");
                failDataList.add(cellData);
                failureNum ++;
            }
        }

        try {
            if (inventoryList != null && inventoryList.size() > 0) { //批量插入数据
                this.saveBatch(inventoryList, inventoryList.size());
                //异步计量单位
                updateInventory(inventoryList, userInfo.getCompanyId());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        String[] excelField = {"物料编码", "物料名称", "规格型号","计量方式", "计量单位组", "计量单位", "允许外购", "允许销售", "允许自制", "允许委外", "允许生产耗用", "允许劳务费用", "允许成套件", "最低库存", "最高库存", "安全库存", "采购提前期(天)", "计价方式"};
        Map result = new HashMap();
        result.put("failNum", failureNum);
        result.put("successNum", successNum);
        result.put("excelField", excelFiled);
        result.put("failData", failDataList);
        result.put("failCause", failCauseList);
        result.put("excelField", excelField);
        return result;
    }

    @Override
    public List<Map<String, String>> getInventoryImportFiled() {
        Integer accountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        List<Map<String, String>> inFiledList = baseMapper.getInventoryImportFiled(userInfo.getCompanyId(), accountId);
        return inFiledList;
    }

    @Override
    public void exportData(Integer classId, HttpServletResponse response) {
        String classCode = "";
        UserInfo userInfo = UserThreadLocal.get();
        String fileName = "物料档案.xls";
        Object[] title = {"物料编码", "物料名称", "规格型号", "物料属性","物料分类", "计量方式", "计量单位组", "计量单位", "最低库存", "最高库存", "安全库存", "采购提前期(天)", "计价方式"};
        String[] inField = {"inventory_code", "inventory_name", "inventory_specification", "properties","inventory_class_name", "unit_type", "unit_group_name", "unit_name", "min_storage"
                , "max_storage", "safe_storage", "purchasing_lead_time", "pricing_method" };

        if(classId != null) {
            InInventoryClass inventoryClass = inventoryClassService.getById(classId);
            classCode = inventoryClass.getClassCode();
        }
        List<HashMap<String, Object>> crmList = baseMapper.getInventoryList(userInfo.getCompanyId(), classCode);
        ExcelUtils.exportData(title, fileName, crmList,inField, response);
    }

    @Override
    public void updatePrice(InInventory inventory) {
        baseMapper.updatePrice(inventory);
    }

    @Override
    public InInventoryPropertyVo getInInventoryPropertyVo(Integer id) {
        return baseMapper.getInInventoryPropertyVo(id);
    }

    @Override
    public String getCommodityAttribute(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        String commodityAttribute = baseMapper.getCommodityAttribute(userInfo.getCompanyId(), id);
        return commodityAttribute;
    }

    @Override
    public List<InInventory> listInInventoryControlProperty(Collection<Integer> ids) {
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<InInventory> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","min_storage","abc_class","max_storage","safe_storage",
                "backlog_criteria","loss_rate","turnover_days","latest_turnover_days",
                "sales_days","purchasing_lead_time","cycle_counting","start_count_time",
                "last_count_time","storage_on_hand","in_storage_up_limit","out_storage_up_limit");
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.in("id",ids);
        return list(queryWrapper);
    }

    @Override
    @Transactional
    public void dAllOrder() {
        String[] tableName = {"mab_bom_detail", "mab_bom", "scw_delivery_entry_detail", "scp_receiving_detail", "scp_invoice_detail", "scp_order_detail", "ma_prod_order_detail",
                "scp_requisition_detail", "scs_delivery_detail", "scs_invoice_detail", "scs_order_detail", "scs_quotation_detail", "ma_picking_return_rep_detail", "ma_completed_prod_detail",
                "ma_prod_order_detail", "ma_mps_detail", "ma_written_instruction_detail",
                "scw_delivery_entry", "scp_receiving", "scp_invoice", "scp_order", "ma_prod_order",
                "scp_requisition", "scs_delivery", "scs_invoice", "scs_order", "scs_quotation", "ma_picking_return_rep", "ma_completed_prod",
                "ma_prod_order", "ma_mps", "ma_written_instruction", "scw_current_stock","scb_material_archive","scb_material_category"};
        for(int i=0; i<tableName.length; i++) {
            baseMapper.deleteOrder(tableName[i], 195);
        }
    }

    @Async
    public void updateInventory( List<InInventory> inventoryList, Integer companyId) {
        for(InInventory inventory : inventoryList) {
            InUnit unit = null;
            if(inventory.getUnitType().equals("单计量")) {
                inventory.setUnitGroupName("");
                unit = unitMapper.getByName(inventory.getUnitName(), companyId);
                if(unit != null) {
                    inventory.setUnitId(unit.getId().intValue());
                }
            } else {
                InUnitGroup group = unitMapper.getGroupByName(inventory.getUnitGroupName(), companyId);
                if(group != null) {
                    inventory.setUnitName("");
                    inventory.setUnitGroupId(group.getId().intValue());
                    inventory.setUnitGroupName(group.getName());
                    //主计量
                    InUnit mUnit = unitMapper.getMainUnit(group.getId());
                    inventory.setMainUnit(mUnit.getId().intValue());
                    inventory.setMainUnitName(mUnit.getName());
                    //辅计量
                    unit = unitMapper.getUnitByGroup(group.getId().intValue());
                }
            }

            if(unit != null) {
                inventory.setPurUnit(unit.getId().intValue());
                inventory.setPurUnitName(unit.getName());
                inventory.setCostUnit(unit.getId().intValue());
                inventory.setCostUnitName(unit.getName());
                inventory.setInUnit(unit.getId().intValue());
                inventory.setInUnitName(unit.getName());
                inventory.setProUnit(unit.getId().intValue());
                inventory.setProUnitName(unit.getName());
                inventory.setSaleUnit(unit.getId().intValue());
                inventory.setSaleUnitName(unit.getName());
                inventory.setRetailUnit(unit.getId().intValue());
                inventory.setRetailUnitName(unit.getName());
            }
        }

        saveOrUpdateBatch(inventoryList, inventoryList.size());
    }

    public Boolean checkInventory(InInventory inventory, List<String> failCauseList, int r, List<String> unitNameList, List<String> groupNameList) {
        if(inventory == null || StringUtils.isBlank(inventory.getInventoryName())) {
            failCauseList.add("第" + (r + 1) + "行:" + "存货名称不能为空");
            return false;
        }

        if(StringUtils.isBlank(inventory.getInventorySpecification())) {
            failCauseList.add("第" + (r + 1) + "行:" + "规格型号不能为空");
            return false;
        }

        if(StringUtils.isBlank(inventory.getUnitType())) {
            failCauseList.add("第" + (r + 1) + "行:" + "计量方式不能为空");
            return false;
        }


        if(inventory.getUnitType().equals("单计量")) {
            if(StringUtils.isBlank(inventory.getUnitName())) {
                failCauseList.add("第" + (r + 1) + "行:" + "计量名称不能为空");
                return false;
            }

            if(!unitNameList.contains(inventory.getUnitName())) {
                failCauseList.add("第" + (r + 1) + "行:" + "计量名称不存在");
                return false;
            }
        } else {
            if(StringUtils.isBlank(inventory.getUnitGroupName())) {
                failCauseList.add("第" + (r + 1) + "行:" + "计量单位组不能为空");
            }

            if(!groupNameList.contains(inventory.getUnitGroupName())) {
                failCauseList.add("第" + (r + 1) + "行:" + "计量组名称不存在");
                return false;
            }
        }

        return true;
    }
}
